package com.livegoods.service.impl;

import com.livegoods.pojo.House;
import com.livegoods.pojo.HouseES;
import com.livegoods.pojo.LivegoodsResult;
import com.livegoods.service.HouseService;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class HouseServiceImpl implements HouseService {

    @Value("${livegoods.fastdfs.nginx}")
    private String nginxHost;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    /**
     * 初始化搜索引擎数据思路，查询MongoDB出所有的数据，循环设置到ES搜索引擎中
     */
    @Override
    public long init() {

        //获取当前时间
        long before = System.currentTimeMillis();

        //查询出所有MongoDB数据
        List<House> houses = mongoTemplate.find(new Query(), House.class);

        //创建List集合封装 IndexQuery
        List<IndexQuery> indexQueries = new ArrayList<>();
        for (House house : houses) {

            //创建IndexQuery对象用于封装HouseES对象
            IndexQuery indexQuery = new IndexQuery();
            //创建搜索引擎对象HouseES,数据来源于 House对象

            HouseES houseES = new HouseES();
            houseES.setId(house.getId());
            houseES.setCity(house.getCity());
            houseES.setTitle(house.getTitle());
            //houseType: "17/19层| 4室1厅 - 273.97 ㎡",
            houseES.setHouseType(house.getInfo().get("type")+" | "+house.getInfo().get("level")+" - "+house.getHouseType());
            houseES.setPrice("<h3>"+house.getPrice()+"</h3>");
            houseES.setImg(house.getImgs()[0]);
            houseES.setRentType(house.getRentType());


            indexQuery.setObject(houseES);

            indexQueries.add(indexQuery);
        }

        //第一次必须先创建索引设置mapping
        elasticsearchRestTemplate.createIndex(HouseES.class);
        elasticsearchRestTemplate.putMapping(HouseES.class);


        elasticsearchRestTemplate.bulkIndex(indexQueries);
        //获取当前时间
        long after = System.currentTimeMillis();

        return after-before;
    }

    @Override
    public LivegoodsResult search(String city, String content, int page) {


        try {
            //创建搜索构建对象
            NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();


            //创建高亮构建对象
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.preTags("<span style='color:red'>");
            highlightBuilder.postTags("</span>");
            //设置分段和长度
            highlightBuilder.fragmentSize(10);//设置分段长度
            highlightBuilder.numOfFragments(1);//返回1个分段
            //将高亮设置构建对象中
            builder.withHighlightBuilder(highlightBuilder);


            //构建条件搜索对象，分别从三列中或者查询
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            //创建集合分别设置三列搜索
            List<QueryBuilder> queryBuilders = new ArrayList<>();
            queryBuilders.add( QueryBuilders.matchQuery("title",content));
            queryBuilders.add(QueryBuilders.matchQuery("houseType",content));
            queryBuilders.add(QueryBuilders.matchQuery("rentType",content));

            //设置三个条件为或者
            boolQueryBuilder.should().addAll(queryBuilders);

            //将城市条件设置为并且关系
            boolQueryBuilder.must(QueryBuilders.matchQuery("city",city));

            //将条件索索的三个或者条件添加构建条件对象中
            builder.withQuery(boolQueryBuilder);
            //分页
            builder.withPageable(PageRequest.of(page,20));


            //构建搜索对象
            NativeSearchQuery searchQuery = builder.build();

            //使用ES的分页高亮查询
            AggregatedPage<HouseES> aggregate = elasticsearchRestTemplate.queryForPage(searchQuery, HouseES.class, new SearchResultMapper() {

                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                    //获取相应的高亮所有数据
                    SearchHit[] hits = response.getHits().getHits();

                    //创建List 添加HouseEs 对象
                    List<HouseES> houseESList = new ArrayList<>();

                    for (SearchHit hit : hits) {
                        //获取普通数据
                        Map<String, Object> sourceAsMap =   hit.getSourceAsMap();

                        //创建HouseES对象，封装数据
                        HouseES houseES = new HouseES();
                        houseES.setId(hit.getId());
                        houseES.setRentType(sourceAsMap.get("rentType").toString());
                        houseES.setPrice(sourceAsMap.get("price").toString());
                        houseES.setHouseType(sourceAsMap.get("houseType").toString());
                        houseES.setImg(nginxHost+sourceAsMap.get("img").toString());
                        houseES.setCity(sourceAsMap.get("city").toString());


                        //获取高亮数据
                        Map<String, HighlightField> highlightFields = hit.getHighlightFields();

                        if(highlightFields.containsKey("title")){
                            HighlightField highlightField = highlightFields.get("title");

                            String title = highlightField.getFragments()[0].toString();

                            houseES.setTitle(title);

                            houseESList.add(houseES);
                        }

                    }

                    //获取总数
                    long totalHits = response.getHits().getTotalHits();

                    return new AggregatedPageImpl(houseESList,pageable,totalHits);
                }

                @Override
                public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                    return null;
                }
            });

            int totalPages = aggregate.getTotalPages();
            List<HouseES> houseESList = aggregate.getContent();

            LivegoodsResult livegoodsResult = LivegoodsResult.ok(houseESList);

            //把外界传递page和查询总也是相比较
            if(page < totalPages-1){
                livegoodsResult.setHasMore(true);
            }else{
                livegoodsResult.setHasMore(false);
            }

            return livegoodsResult;
        } catch (Exception e) {
            e.printStackTrace();
            return  LivegoodsResult.error("操作失败...");
        }
    }
}
